#pragma once
#include <iostream>
#include <functional>
#include <cstring>
#include <cerrno>
#include <cstdlib>

#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "Log.hpp"
#include "InetAddr.hpp"
using namespace std;

using func_t=function<string(const string&)>;

enum 
{
    SOCK_ERROR=1,
    BIND_ERROR,
    USAGE_ERROR
};

class UdpServer
{
public:
    UdpServer(uint16_t port,func_t func)
    :_sockfd(-1)
    ,_port(port)
    ,_isrunning(false)
    ,_func(func)
    {}

    void InitServer()
    {
        //1.创建套接字文件
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            LOG(FATAL,"socket error:%s,%d",strerror(errno),errno);
            exit(SOCK_ERROR);
        }
        LOG(INFO,"create socket success");
        //2.将套接字文件与网络信息进行绑定
        //2.0 填充struct sockaddr_in结构
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=htonl(INADDR_ANY);
        //绑定网络信息
        int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind error:%s,%d",strerror(errno),errno);
            exit(BIND_ERROR);
        }
        LOG(INFO,"bind socket success");
    }

    //所有服务器本质解决的是输入输出问题！
    //服务器上面不想采用网络通信模块与业务模块进行强耦合
    //目的:网络模块与业务模块解耦合,实现分层
    void Start()
    {
        _isrunning=true;
        while(_isrunning)
        {
            
            char request[1024];
            struct sockaddr_in peer;
            bzero(&peer,sizeof(peer));
            socklen_t len=sizeof(peer);
            ssize_t n=recvfrom(_sockfd,request,sizeof(request),0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                request[n]=0;
                InetAddr addr  (peer);
                LOG(DEBUG,"[%s:%d],%s",addr.IP().c_str(),addr.Port(),request);

                string response=_func(request);//将客户端的请求回调到上层,由上层处理,服务器只做收发工作
                //回调函数执行结束,将具有返回值response

                sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,sizeof(peer));
            }
        }
        _isrunning=false;
    }
    ~UdpServer()
    {

    }
    
private:
    int _sockfd;
    uint16_t  _port;
    bool _isrunning;

    //服务器内部设定回调方法,上层进行业务处理
    func_t _func;
};